package asia.redact.bracket.properties.mgmt;

/**
 * Sort of like a Locale, but for server environments.
 * 
 * The description of properties with environment localization has the following structure:
 * 
 * For a given properties file:
 * 
 * basename[_environment|*][_cluster|*][_instance|*][_variant|*].properties
 * 
 * where
 * 
 * basename 	is a file name, for example "myprops"
 * 				Note: the base name cannot have underscore characters (this is a limitation 
 * 				of the localization algorithm)
 * _[environment|] where "environment" is any non-empty token such as "dev", "development", 
 * 				"test", "prod", and so on. The empty string matches any environment, null matches none.
 * _[cluster|]	where "cluster" is any non-empty token such as "liferay", "mycluster" and so on.
 * 				The empty string matches any cluster, null matches none.
 * _[instance|]	where "instance" is any non-empty token such as "s1", "s2" and so on 
 * 				The empty string matches any environment, null matches none.
 * _[variant|]	the variant can by any token but is often used for "secure" as a special case
 * 				The empty string matches any environment, null matches none.
 * 
 * Example properties files forming a set of server environment localized properties:
 * 
 * portal-ext.properties						a template of properties across all environments (no environment localization)
 * portal-ext_dev.properties					specific to the dev environment
 * portal-ext_dev_liferay.properties			specific to the dev liferay cluster
 * portal-ext_dev_liferay_s1.properties			specific to the dev liferay s1 instance
 * portal-ext_dev_liferay_s2.properties			specific to the dev liferay s2 instance
 * portal-ext_dev_liferay_s3.properties			specific to the dev liferay s3 instance
 * portal-ext_dev_liferay_s4.properties			specific to the dev liferay s4 instance
 * portal-ext_dev_liferay_s4_secure.properties	specific variant to the dev liferay s4 instance with this baseName
 * portal-ext_dev_liferay__secure.properties	variant applied to any dev liferay cluster instance with this baseName
 * portal-ext_dev___secure.properties			variant applied to any dev environnment instance with this baseName
 * portal-ext____secure.properties			    variant - apply these properties to all environments with this baseName
 * portal-ext_____.properties			    	legal but identical in effect to portal-ext.properties
 * 
 * 
 * 
 * 
 * @author Dave
 *
 */
public class ServerLocale {
	
	// empty string is a wildcard, null means not set
	
	String environment, cluster,  instance, variant;
	
	public ServerLocale(String environment, String cluster,  String instance,String variant) {
		super();
		this.environment = environment;
		this.cluster = cluster;
		this.variant = variant;
		this.instance = instance;
		
	}
	
	public ServerLocale(String environment, String cluster, String instance) {
		super();
		this.environment = environment;
		this.cluster = cluster;
		this.instance = instance;
	}
	
	public ServerLocale(String environment, String cluster) {
		super();
		this.environment = environment;
		this.cluster = cluster;
	}
	
	public ServerLocale(String environment) {
		super();
		this.environment = environment;
	}
	
	public ServerLocale() {
		super();
	}

	public String getEnvironment() {
		return environment;
	}

	public void setEnvironment(String environment) {
		this.environment = environment;
	}

	public String getCluster() {
		return cluster;
	}

	public void setCluster(String cluster) {
		this.cluster = cluster;
	}

	public String getInstance() {
		return instance;
	}

	public void setInstance(String instance) {
		this.instance = instance;
	}

	public String getVariant() {
		return variant;
	}

	public void setVariant(String sec) {
		this.variant = sec;
	}
	
	public String toString(){
		StringBuffer buf = new StringBuffer();
		if(isWildcard(environment)){
			buf.append("_");
		}else if(isNotSet(environment)){
			//do nothing
		}else{
			buf.append("_");
			buf.append(environment);
		}
		
		if(isWildcard(cluster)){
			buf.append("_");
		}else if(isNotSet(cluster)){
			//do nothing
		}else{
			buf.append("_");
			buf.append(cluster);
		}
		
		if(isWildcard(instance)){
			buf.append("_");
		}else if(isNotSet(instance)){
			//do nothing
		}else{
			buf.append("_");
			buf.append(instance);
		}
		
		if(isWildcard(variant)){
			buf.append("_");
		}else if(isNotSet(variant)){
			//do nothing
		}else{
			buf.append("_");
			buf.append(variant);
		}
			
		return buf.toString();
	}
	
	boolean isWildcard(String s){
		if(s==null)return false;
		return s.equals("");
	}
	
	boolean isNotSet(String s){
		return s==null;
	}
	
	boolean isSet(String s){
		return s!=null;
	}
	
	boolean matchesEnvironment(String env){
		//if equal and 
		if(this.environment != null && this.environment.equals(env))return true;
		if(this.environment !=null && isWildcard(this.environment) && isSet(env))return true;
		return false;
	}
	
	/**
	 * Collect the baseName, encoded locale, and extension of a file name
	 * 
	 * assume the fileName ends in .properties, fail if this is not so.
	 * 
	 * @param fileName
	 * @return
	 */
	public static ServerLocalizedFileInfo fromFileName(String fileName){
		if(!fileName.endsWith(".properties")) {
			throw new RuntimeException("fileName must be a properties file, end in .properties");
		}
		ServerLocalizedFileInfo info = new ServerLocalizedFileInfo();
		info.extension = ".properties";
		int firstUnderscore = fileName.indexOf("_");
		if(firstUnderscore == -1){
			//we must be a base file
			info.baseName=fileName.substring(11);
			info.locale = new ServerLocale();
		}else{
			info.baseName = fileName.substring(0,firstUnderscore-1);
			String pat = fileName.substring(firstUnderscore-1,fileName.length()-11);
			info.locale= ServerLocale.fromString(pat);
		}
		
		return info;
	}
	
	/**
	 * return a server locale instance parsed from the input
	 * 
	 * The ServerLocale generated will have a toString() method that returns a 
	 * value equal to the input
	 * 
	 * Inputs must match the following patterns:
	 * 
	 * empty string
	 * _[environment|]
	 * _[environment|]_[cluster|]
	 * _[environment|]_[cluster|]_[instance|]
	 * _[environment|]_[cluster|]_[instance|]_[variant|]
	 * 
	 * the tokens for environment, cluster, instance, and variant 
	 * can be anything legal in a file name except an underscore
	 * and are user defined
	 * 
	 * 
	 * @param input a string containing the pattern
	 * @return
	 */
	public static ServerLocale fromString(String input){
		
		ServerLocale locale = new ServerLocale();
		if(input == ""||input==null) return locale;
		
		int underscoreCount = 0;
		StringBuffer environment = new StringBuffer(), 
					cluster=new StringBuffer(),  
					instance=new StringBuffer(), 
					variant=new StringBuffer();
		
		for(char ch : input.toCharArray()){
			if(ch == '_') {
				underscoreCount++;
				continue;
			}
			if(underscoreCount==1){
				environment.append(ch);
			}else if(underscoreCount==2){
				cluster.append(ch);
			}else if(underscoreCount==3){
				instance.append(ch);
			}if(underscoreCount==4){
				variant.append(ch);
			}
		}
		
	if(environment.length()>0)locale.setEnvironment(environment.toString());
	if(cluster.length()>0)locale.setCluster(cluster.toString());
	if(instance.length()>0)locale.setInstance(instance.toString());
	if(variant.length()>0)locale.setVariant(variant.toString());
	
	if(underscoreCount==4){
		//if any are empty, that is a wildcard
		if(environment.length()==0)locale.setEnvironment("");
		if(cluster.length()==0)locale.setCluster("");
		if(instance.length()==0)locale.setInstance("");
		if(variant.length()==0)locale.setVariant("");
	}
	
	if(underscoreCount==3){
		//if any are empty, that is a wildcard
		if(environment.length()==0)locale.setEnvironment("");
		if(cluster.length()==0)locale.setCluster("");
		if(instance.length()==0)locale.setInstance("");
	}
	
	if(underscoreCount==2){
		//if any are empty, that is a wildcard
		if(environment.length()==0)locale.setEnvironment("");
		if(cluster.length()==0)locale.setCluster("");
	}
	
	if(underscoreCount==1){
		//if any are empty, that is a wildcard
		if(environment.length()==0)locale.setEnvironment("");
	}
		
		return locale;
	}
	
	/**
	 * Return true if the fileName pattern is "included" within this locale.
	 * 
	 * A fileName is "included" in a locale if it matches the pattern string of the locale.
	 * 
	 * A ServerLocale pattern may include wildcards (represented by the empty string for any or all of the values). E.g.:
	 * String representation: _dev___. This means the "dev" environment and wildcards for the other values. 
	 * The pattern baseName_prod___ would include the files
	 * baseName_prod.properties, baseName_prod_cluster1.properties, baseName_prod_cluster2.properties, and
	 * baseName_prod_cluster1_inst1.properties. It would not include baseName_dev.properties.
	 * 
	 * 
	 * A ServerLocale may also include null values which represent the value as uninitialized or undefined. 
	 * For example, the locale pattern baseName_prod would include the file baseName_prod.properties 
	 * but not baseName_prod_cluster1.properties. 
	 * 
	 * 
	 * 
	 * @param fileName
	 * @return
	 */
	
	public boolean includes(String fileName){
		
		ServerLocalizedFileInfo info = ServerLocale.fromFileName(fileName);
		//if(this.environment==info.loca
		
		
		
		return false;
	}


	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((cluster == null) ? 0 : cluster.hashCode());
		result = prime * result
				+ ((environment == null) ? 0 : environment.hashCode());
		result = prime * result
				+ ((instance == null) ? 0 : instance.hashCode());
		result = prime * result + ((variant == null) ? 0 : variant.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ServerLocale other = (ServerLocale) obj;
		if (cluster == null) {
			if (other.cluster != null)
				return false;
		} else if (!cluster.equals(other.cluster))
			return false;
		if (environment == null) {
			if (other.environment != null)
				return false;
		} else if (!environment.equals(other.environment))
			return false;
		if (instance == null) {
			if (other.instance != null)
				return false;
		} else if (!instance.equals(other.instance))
			return false;
		if (variant == null) {
			if (other.variant != null)
				return false;
		} else if (!variant.equals(other.variant))
			return false;
		return true;
	}
	
	
}
